#define TRACE
using Dapper;
using MySql.Data.MySqlClient;
using DapperExtensionsNew.Builders;
using DapperExtensionsNew.Configuration;
using DapperExtensionsNew.Data;
using DapperExtensionsNew.Data.Attributes;
using DapperExtensionsNew.Data.Descriptors;
using DapperExtensionsNew.Queryable;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static Dapper.SqlMapper;

namespace DapperExtensionsNew
{
	public class AbstractRepository<T> : IRepository<T> where T : new()
	{
		protected string ConnectionString;

		protected string SlaveConnectionString;

		private DbType _dbType;

		private SqlDatabaseOptions _sqlDatabaseOptions;

		protected AbstractRepository()
		{
			TableAttribute table = TableCache.GetTable(typeof(T));
			SetDbType(table.Analyzer);
			if (!string.IsNullOrEmpty(table.Db) && ConnectionString == null)
			{
				ConnectionString = ConnectionStringConfig.GetConnectionString(table.Db);
				SlaveConnectionString = ConnectionStringConfig.GetConnectionString(table.Db + "ReadOnly");
			}
		}

		protected void SetDbType(DbType type)
		{
			_dbType = type;
			_sqlDatabaseOptions = SqlDatabaseOptionsFactory.GetSqlDatabaseOptions(_dbType);
		}

		protected void OpenConnection(Action<IDbConnection> action)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (_dbType == DbType.MySql)
			{
                using (MySqlConnection connection = new MySqlConnection(ConnectionString))
                {
                    connection.Open();
                    action(connection);
                }
            }
			else
			{
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    connection.Open();
                    action(connection);
                }
            }
		}

		protected void OpenSlaveConnection(Action<IDbConnection> action)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (_dbType == DbType.MySql)
			{
                using (MySqlConnection connection = new MySqlConnection(SlaveConnectionString))
                {
                    connection.Open();
                    action(connection);
                }
            }
			else
			{
                using (SqlConnection connection = new SqlConnection(SlaveConnectionString))
                {
                    connection.Open();
                    action(connection);
                }
            }
		}

		protected async Task OpenConnectionAsync(Func<IDbConnection, Task> action)
		{
			if (_dbType == DbType.MySql)
			{
				using (MySqlConnection connection = new MySqlConnection(ConnectionString))
				{
					await connection.OpenAsync();
					await action(connection);
				}
			}
			else
			{
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    await connection.OpenAsync();
                    await action(connection);
                }
            }
		}

		protected async Task OpenSlaveConnectionAsync(Func<IDbConnection, Task> action)
		{
			if (_dbType == DbType.MySql)
			{
				using (MySqlConnection connection = new MySqlConnection(SlaveConnectionString))
				{
                    await connection.OpenAsync();
                    await action(connection);
                }
			}
			else
			{
                using (SqlConnection connection = new SqlConnection(SlaveConnectionString))
                {
                    await connection.OpenAsync();
                    await action(connection);
                }
            }
		}

		public int Insert(T obj)
		{
			return Insert(obj, null, null);
		}

		public int Insert<TEntity>(TEntity obj)
		{
			return Insert(obj, null, null);
		}

		public TKey Insert<TKey>(T obj)
		{
			return Insert<TKey, T>(obj, null, null);
		}

		public TKey Insert<TKey, TEntity>(TEntity obj)
		{
			return Insert<TKey, TEntity>(obj, null, null);
		}

		public void InsertBatch<TEntity>(IEnumerable<TEntity> entities)
		{
			InsertBatch(entities, null, null);
		}

		public int Update(T obj, IEnumerable<string> updateFields = null)
		{
			return Update(obj, updateFields, null, null);
		}

		public int Update<TEntity>(TEntity obj, IEnumerable<string> updateFields = null)
		{
			return Update(obj, updateFields, null, null);
		}

		public int Delete(object id, string opName = "", bool isDelete = false)
		{
			return Delete<T>(id, isDelete, opName);
		}

		public int Delete<TEntity>(object id, string opName = "", bool isDelete = false)
		{
			return Delete<TEntity>(id, isDelete, opName);
		}

		public int DeleteList(object whereConditions, string opName = "", bool isDelete = false)
		{
			return DeleteList<T>(whereConditions, isDelete, opName);
		}

		public int DeleteList<TEntity>(object whereConditions, string opName = "", bool isDelete = false)
		{
			return DeleteList<TEntity>(whereConditions, isDelete, opName);
		}

		public int DeleteList(string conditions, object parameters = null, string opName = "", bool isDelete = false)
		{
			return DeleteList<T>(conditions, isDelete, opName, parameters);
		}

		public int DeleteList<TEntity>(string conditions, object parameters = null, string opName = "", bool isDelete = false)
		{
			return DeleteList<TEntity>(conditions, isDelete, opName, parameters);
		}

		public T Get(object id, bool useMaster = false)
		{
			return Get<T>(id, null, null, useMaster);
		}

		public TEntity Get<TEntity>(object id, bool useMaster = false)
		{
			return Get<TEntity>(id, null, null, useMaster);
		}

		public IEnumerable<T> GetList(object whereConditions, bool useMaster = false)
		{
			return GetList<T>(whereConditions, null, null, useMaster);
		}

		public IEnumerable<TEntity> GetList<TEntity>(object whereConditions, bool useMaster = false)
		{
			return GetList<TEntity>(whereConditions, null, null, useMaster);
		}

		public IEnumerable<T> GetList(string conditions, object parameters = null, bool useMaster = false)
		{
			return GetList<T>(conditions, parameters, null, null, useMaster);
		}

		public IEnumerable<TEntity> GetList<TEntity>(string conditions, object parameters = null, bool useMaster = false)
		{
			return GetList<TEntity>(conditions, parameters, null, null, useMaster);
		}

		public PagedEntity<T> GetListPaged(int pageNumber, int pageSize, string conditions, string orderby, object parameters = null, bool useMaster = false)
		{
			return GetListPaged<T>(pageNumber, pageSize, conditions, orderby, parameters, null, null, useMaster);
		}

		public PagedEntity<TEntity> GetListPaged<TEntity>(int pageNumber, int pageSize, string conditions, string orderby, object parameters = null, bool useMaster = false)
		{
			return GetListPaged<TEntity>(pageNumber, pageSize, conditions, orderby, parameters, null, null, useMaster);
		}

		public int RecordCount(string conditions, object parameters = null, bool useMaster = false)
		{
			return RecordCount<T>(conditions, parameters, null, null, useMaster);
		}

		public int RecordCount<TEntity>(string conditions, object parameters = null, bool useMaster = false)
		{
			return RecordCount<TEntity>(conditions, parameters, null, null, useMaster);
		}

		public int RecordCount(object whereConditions, bool useMaster = false)
		{
			return RecordCount<T>(whereConditions, null, null, useMaster);
		}

		public int RecordCount<TEntity>(object whereConditions, bool useMaster = false)
		{
			return RecordCount<TEntity>(whereConditions, null, null, useMaster);
		}

		private TEntity Get<TEntity>(object id, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			List<ColumnDescriptor> list = columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList();
			if (!list.Any())
			{
				throw new ArgumentException("Get<TEntity> only supports an entity with a [Key] or Id property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			sb.Append("Select ");
			BuildSelect(sb, columnDescriptors);
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			sb.Append(" where ");
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0)
				{
					sb.Append(" and ");
				}
				sb.AppendFormat("{0} = @{1}", Encapsulate(list[i].DbName), list[i].Name);
			}
			BuildIsDeleted(sb, columnDescriptors);
			DynamicParameters dynParms = (DynamicParameters)(object)new DynamicParameters();
			if (list.Count == 1)
			{
				dynParms.Add("@" + list.First().Name, id, (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
			}
			else
			{
				foreach (ColumnDescriptor item in list)
				{
					dynParms.Add("@" + item.Name, id.GetType().GetProperty(item.Name).GetValue(id, null), (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
				}
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Get<{typeFromHandle}>: {sb} with Id: {id}");
			}
			TEntity entity = (TEntity)default(TEntity);
			if (useMaster)
			{
				OpenConnection(delegate(IDbConnection conn)
				{
					entity = (TEntity)SqlMapper.Query<TEntity>(conn, sb.ToString(), (object)dynParms, transaction, true, commandTimeout, (CommandType?)null).FirstOrDefault();
				});
			}
			else
			{
				OpenSlaveConnection(delegate(IDbConnection conn)
				{
					entity = (TEntity)SqlMapper.Query<TEntity>(conn, sb.ToString(), (object)dynParms, transaction, true, commandTimeout, (CommandType?)null).FirstOrDefault();
				});
			}
			return (TEntity)entity;
		}

		private IEnumerable<TEntity> GetList<TEntity>(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			if (!columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList().Any())
			{
				throw new ArgumentException("Get<TEntity> only supports an entity with a [Key] or Id property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			PropertyInfo[] array = whereConditions.GetAllProperties().ToArray();
			sb.Append("Select ");
			BuildSelect(sb, columnDescriptors);
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			if (array.Any())
			{
				sb.Append(" where ");
				BuildWhere<TEntity>(sb, array, whereConditions);
			}
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"GetList<{typeFromHandle}>: {sb}");
			}
			IEnumerable<TEntity> entities = null;
			if (useMaster)
			{
				OpenConnection(delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)SqlMapper.Query<TEntity>(conn, sb.ToString(), whereConditions, transaction, true, commandTimeout, (CommandType?)null);
				});
			}
			else
			{
				OpenSlaveConnection(delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)SqlMapper.Query<TEntity>(conn, sb.ToString(), whereConditions, transaction, true, commandTimeout, (CommandType?)null);
				});
			}
			return (IEnumerable<TEntity>)entities;
		}

		private IEnumerable<TEntity> GetList<TEntity>(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			if (!columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList().Any())
			{
				throw new ArgumentException("Get<TEntity> only supports an entity with a [Key] or Id property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			sb.Append("Select ");
			BuildSelect(sb, columnDescriptors);
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			sb.Append(" " + conditions);
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"GetList<{typeFromHandle}>: {sb}");
			}
			IEnumerable<TEntity> entities = null;
			if (useMaster)
			{
				OpenConnection(delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)SqlMapper.Query<TEntity>(conn, sb.ToString(), parameters, transaction, true, commandTimeout, (CommandType?)null);
				});
			}
			else
			{
				OpenSlaveConnection(delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)SqlMapper.Query<TEntity>(conn, sb.ToString(), parameters, transaction, true, commandTimeout, (CommandType?)null);
				});
			}
			return (IEnumerable<TEntity>)entities;
		}

		private PagedEntity<TEntity> GetListPaged<TEntity>(int pageNumber, int pageSize, string conditions, string orderby, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			if (string.IsNullOrEmpty(_sqlDatabaseOptions.PagedListSql))
			{
				throw new Exception("GetListPage is not supported with the current SQL Dialect");
			}
			if (pageNumber < 1)
			{
				throw new Exception("Page must be greater than 0");
			}
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			List<ColumnDescriptor> source = columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList();
			if (!source.Any())
			{
				throw new ArgumentException("Get<TEntity> only supports an entity with a [Key] or Id property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder stringBuilder = new StringBuilder();
			string query = _sqlDatabaseOptions.PagedListSql;
			if (string.IsNullOrEmpty(orderby))
			{
				orderby = Encapsulate(source.First().DbName);
			}
			List<ColumnDescriptor> props = columnDescriptors;
			BuildSelect(stringBuilder, props);
			query = query.Replace("{SelectColumns}", stringBuilder.ToString());
			query = query.Replace("{TableName}", tableName);
			query = query.Replace("{PageNumber}", pageNumber.ToString());
			query = query.Replace("{RowsPerPage}", pageSize.ToString());
			query = query.Replace("{OrderBy}", orderby);
			query = query.Replace("{WhereClause}", conditions);
			query = query.Replace("{IsDeleted}", BuildIsDeleted(null, props, query));
			query = query.Replace("{Offset}", ((pageNumber - 1) * pageSize).ToString());
			string countQuery = _sqlDatabaseOptions.PagedListCountSql;
			countQuery = countQuery.Replace("{TableName}", tableName);
			countQuery = countQuery.Replace("{WhereClause}", conditions);
			countQuery = countQuery.Replace("{IsDeleted}", BuildIsDeleted(null, props, countQuery));
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"GetListPaged<{typeFromHandle}>: {query},{countQuery}");
			}
			PagedEntity<TEntity> entities = (PagedEntity<TEntity>)(object)new PagedEntity<TEntity>();
			((PagedEntity<TEntity>)(object)entities).Items = new List<TEntity>();
			if (useMaster)
			{
				OpenConnection(delegate(IDbConnection conn)
				{
					((PagedEntity<TEntity>)(object)entities).TotalItems = SqlMapper.Query<int>(conn, countQuery, parameters, transaction, true, commandTimeout, (CommandType?)null).FirstOrDefault();
					if (((PagedEntity<TEntity>)(object)entities).TotalItems != 0)
					{
						((PagedEntity<TEntity>)(object)entities).Items = SqlMapper.Query<TEntity>(conn, query, parameters, transaction, true, commandTimeout, (CommandType?)null).ToList();
					}
				});
			}
			else
			{
				OpenSlaveConnection(delegate(IDbConnection conn)
				{
					((PagedEntity<TEntity>)(object)entities).TotalItems = SqlMapper.Query<int>(conn, countQuery, parameters, transaction, true, commandTimeout, (CommandType?)null).FirstOrDefault();
					if (((PagedEntity<TEntity>)(object)entities).TotalItems != 0)
					{
						((PagedEntity<TEntity>)(object)entities).Items = SqlMapper.Query<TEntity>(conn, query, parameters, transaction, true, commandTimeout, (CommandType?)null).ToList();
					}
				});
			}
			return (PagedEntity<TEntity>)(object)entities;
		}

		private int Insert<TEntity>(TEntity entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			return Insert<int, TEntity>(entityToInsert, transaction, commandTimeout);
		}

		private TKey Insert<TKey, TEntity>(TEntity entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			List<ColumnDescriptor> source = GetIdProperties(entityToInsert).ToList();
			if (!source.Any())
			{
				throw new ArgumentException("Insert<T> only supports an entity with a [Key] or Id property");
			}
			bool flag = false;
			Type typeFromHandle = typeof(TKey);
			Type left = Nullable.GetUnderlyingType(typeFromHandle) ?? typeFromHandle;
			if (left != typeof(int) && left != typeof(uint) && left != typeof(long) && left != typeof(ulong) && left != typeof(short) && left != typeof(ushort) && left != typeof(Guid) && left != typeof(string))
			{
				throw new Exception("Invalid return type");
			}
			string tableName = GetTableName(entityToInsert);
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("insert into {0}", tableName);
			sb.Append(" (");
			BuildInsertParameters<TEntity>(sb);
			sb.Append(") ");
			sb.Append("values");
			sb.Append(" (");
			BuildInsertValues<TEntity>(sb);
			sb.Append(")");
			if (left == typeof(string))
			{
				if (string.IsNullOrEmpty((string)source.First().GetKeyValue(entityToInsert)))
				{
					string arg = SequentialGuid().ToString("N");
					source.First().SetKeyValue(entityToInsert, arg);
				}
				else
				{
					flag = true;
				}
				sb.Append(";select '" + source.First().GetKeyValue(entityToInsert)?.ToString() + "' as id");
			}
			else if (left == typeof(Guid))
			{
				if ((Guid)source.First().GetKeyValue(entityToInsert) == Guid.Empty)
				{
					Guid guid = SequentialGuid();
					source.First().SetKeyValue(entityToInsert, guid);
				}
				else
				{
					flag = true;
				}
				sb.Append(";select '" + source.First().GetKeyValue(entityToInsert)?.ToString() + "' as id");
			}
			else if (left == typeof(int) || left == typeof(long))
			{
				if (Convert.ToInt64(source.First().GetKeyValue(entityToInsert)) == 0L)
				{
					sb.Append(";" + _sqlDatabaseOptions.IdentitySql);
				}
				else
				{
					sb.Append(";select " + source.First().GetKeyValue(entityToInsert)?.ToString() + " as id");
					flag = true;
				}
			}
			else
			{
				flag = true;
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Insert: {sb}");
			}
			IEnumerable<dynamic> entities = null;
			OpenConnection(delegate(IDbConnection conn)
			{
				entities = SqlMapper.Query(conn, sb.ToString(), (object)entityToInsert, transaction, true, commandTimeout, (CommandType?)null);
			});
			if ((left == typeof(Guid) || left == typeof(string)) | flag)
			{
				return (TKey)source.First().GetKeyValue(entityToInsert);
			}
			dynamic val = entities.First().id;
			if (source.First().TypeName == "Int64")
			{
				source.First().SetKeyValue(entityToInsert, (long)val);
			}
			else
			{
				source.First().SetKeyValue(entityToInsert, (int)val);
			}
			return (TKey)val;
		}

		private void InsertBatch<TEntity>(IEnumerable<TEntity> entities, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			string tableName = GetTableName(entities.FirstOrDefault());
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("insert into {0}", tableName);
			sb.Append(" (");
			BuildInsertParameters<TEntity>(sb);
			sb.Append(") ");
			sb.Append("values");
			sb.Append(" (");
			BuildInsertValues<TEntity>(sb);
			sb.Append(")");
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Insert: {sb}");
			}
			OpenConnection(delegate(IDbConnection conn)
			{
				SqlMapper.Execute(conn, sb.ToString(), (object)entities, transaction, commandTimeout, (CommandType?)null);
			});
		}

		private int Update<TEntity>(TEntity entityToUpdate, IEnumerable<string> updateFields = null, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			List<ColumnDescriptor> list = GetIdProperties(entityToUpdate).ToList();
			if (!list.Any())
			{
				throw new ArgumentException("Entity must have at least one [Key] or Id property");
			}
			string tableName = GetTableName(entityToUpdate);
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("update {0}", tableName);
			sb.AppendFormat(" set ");
			BuildUpdateSet<TEntity>(sb, updateFields);
			sb.Append(" where ");
			BuildKeyWhere<TEntity>(sb, list);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Update: {sb}");
			}
			int result = 0;
			OpenConnection(delegate(IDbConnection conn)
			{
				result = SqlMapper.Execute(conn, sb.ToString(), (object)entityToUpdate, transaction, commandTimeout, (CommandType?)null);
			});
			return result;
		}

		private int Delete<TEntity>(object id, bool isDelete = false, string opName = "", IDbTransaction transaction = null, int? commandTimeout = null)
		{
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			List<ColumnDescriptor> list = columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList();
			if (!list.Any())
			{
				throw new ArgumentException("Get<TEntity> only supports an entity with a [Key] or Id property");
			}
			ColumnDescriptor columnDescriptor = columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "IsDeleted");
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			if (!isDelete && columnDescriptor != null)
			{
				if (columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "Operator") != null && !string.IsNullOrEmpty(opName))
				{
					sb.AppendFormat("Update {0} set IsDeleted=1,Operator='{1}' where IsDeleted=0 and ", tableName, opName);
				}
				else
				{
					sb.AppendFormat("Update {0} set IsDeleted=1 where IsDeleted=0 and ", tableName);
				}
			}
			else
			{
				sb.AppendFormat("Delete from {0} where ", tableName);
			}
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0)
				{
					sb.Append(" and ");
				}
				sb.AppendFormat("{0} = @{1}", Encapsulate(list[i].DbName), list[i].Name);
			}
			DynamicParameters dynParms = (DynamicParameters)(object)new DynamicParameters();
			if (list.Count == 1)
			{
				dynParms.Add("@" + list.First().Name, id, (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
			}
			else
			{
				foreach (ColumnDescriptor item in list)
				{
					dynParms.Add("@" + item.Name, id.GetType().GetProperty(item.Name).GetValue(id, null), (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
				}
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Delete<{typeFromHandle}> {sb}");
			}
			int result = 0;
			OpenConnection(delegate(IDbConnection conn)
			{
				result = SqlMapper.Execute(conn, sb.ToString(), (object)dynParms, transaction, commandTimeout, (CommandType?)null);
			});
			return result;
		}

		private int DeleteList<TEntity>(object whereConditions, bool isDelete = false, string opName = "", IDbTransaction transaction = null, int? commandTimeout = null)
		{
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			ColumnDescriptor columnDescriptor = columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "IsDeleted");
			StringBuilder sb = new StringBuilder();
			if (!isDelete && columnDescriptor != null)
			{
				if (columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "Operator") != null && !string.IsNullOrEmpty(opName))
				{
					sb.AppendFormat("Update {0} set IsDeleted=1,Operator='{1}' where IsDeleted=0 ", tableName, opName);
				}
				else
				{
					sb.AppendFormat("Update {0} set IsDeleted=1 where IsDeleted=0 ", tableName);
				}
			}
			else
			{
				sb.AppendFormat("Delete from {0} where 1=1 ", tableName);
			}
			PropertyInfo[] array = whereConditions.GetAllProperties().ToArray();
			if (array.Any())
			{
				sb.Append(" and ");
				BuildWhere<TEntity>(sb, array);
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"DeleteList<{typeFromHandle}> {sb}");
			}
			int deleteCount = 0;
			OpenConnection(delegate(IDbConnection conn)
			{
				deleteCount = SqlMapper.Execute(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null);
			});
			return deleteCount;
		}

		private int DeleteList<TEntity>(string conditions, bool isDelete = false, string opName = "", object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			if (string.IsNullOrEmpty(conditions))
			{
				throw new ArgumentException("DeleteList<T> requires a where clause");
			}
			if (!conditions.ToLower().Contains("where"))
			{
				throw new ArgumentException("DeleteList<T> requires a where clause and must contain the WHERE keyword");
			}
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			ColumnDescriptor columnDescriptor = columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "IsDeleted");
			StringBuilder sb = new StringBuilder();
			if (!isDelete && columnDescriptor != null)
			{
				if (columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "Operator") != null && !string.IsNullOrEmpty(opName))
				{
					sb.AppendFormat("Update {0} set IsDeleted=1,Operator='{1}'", tableName, opName);
				}
				else
				{
					sb.AppendFormat("Update {0} set IsDeleted=1", tableName);
				}
			}
			else
			{
				sb.AppendFormat("Delete from {0}", tableName);
			}
			sb.Append(" " + conditions);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"DeleteList<{typeFromHandle}> {sb}");
			}
			int deleteCount = 0;
			OpenConnection(delegate(IDbConnection conn)
			{
				deleteCount = SqlMapper.Execute(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null);
			});
			return deleteCount;
		}

		private int RecordCount<TEntity>(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			sb.Append("Select count(1)");
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			sb.Append(" " + conditions);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"RecordCount<{typeFromHandle}>: {sb}");
			}
			int count = 0;
			if (useMaster)
			{
				OpenConnection(delegate(IDbConnection conn)
				{
					count = SqlMapper.ExecuteScalar<int>(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null);
				});
			}
			else
			{
				OpenSlaveConnection(delegate(IDbConnection conn)
				{
					count = SqlMapper.ExecuteScalar<int>(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null);
				});
			}
			return count;
		}

		private int RecordCount<TEntity>(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			PropertyInfo[] array = whereConditions.GetAllProperties().ToArray();
			sb.Append("Select count(1)");
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			if (array.Any())
			{
				sb.Append(" where ");
				BuildWhere<TEntity>(sb, array, (TEntity)Activator.CreateInstance(typeof(TEntity)));
			}
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"RecordCount<{typeFromHandle}>: {sb}");
			}
			int count = 0;
			if (useMaster)
			{
				OpenConnection(delegate(IDbConnection conn)
				{
					count = SqlMapper.ExecuteScalar<int>(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null);
				});
			}
			else
			{
				OpenSlaveConnection(delegate(IDbConnection conn)
				{
					count = SqlMapper.ExecuteScalar<int>(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null);
				});
			}
			return count;
		}

		private string BuildIsDeleted(StringBuilder sb, IEnumerable<ColumnDescriptor> props, string query = "")
		{
			ColumnDescriptor columnDescriptor = props.FirstOrDefault((ColumnDescriptor o) => o.IsDeletedKey);
			if (columnDescriptor != null)
			{
				if (columnDescriptor.IsNotGenWhereCondition)
				{
					return "";
				}
				string dbName = columnDescriptor.DbName;
				if (!string.IsNullOrEmpty(query))
				{
					if (query.IndexOf("where", StringComparison.OrdinalIgnoreCase) == -1)
					{
						return " where " + dbName + "=0 ";
					}
					return " and " + dbName + "=0 ";
				}
				string text = sb.ToString();
				sb.Append((text.IndexOf("where", StringComparison.OrdinalIgnoreCase) != -1) ? (" and " + dbName + "=0 ") : (" where " + dbName + "=0 "));
			}
			return "";
		}

		private void BuildUpdateSet<TEntity>(StringBuilder sb, IEnumerable<string> updateFields)
		{
			ColumnDescriptor[] array = GetUpdateableProperties<TEntity>(updateFields).ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				ColumnDescriptor columnDescriptor = array[i];
				sb.AppendFormat("{0} = @{1}", Encapsulate(columnDescriptor.DbName), columnDescriptor.Name);
				if (i < array.Length - 1)
				{
					sb.AppendFormat(", ");
				}
			}
		}

		private void BuildSelect(StringBuilder sb, IEnumerable<ColumnDescriptor> props)
		{
			List<ColumnDescriptor> list = props.ToList();
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				ColumnDescriptor columnDescriptor = list.ElementAt(i);
				if (flag)
				{
					sb.Append(",");
				}
				sb.Append(Encapsulate(columnDescriptor.DbName));
				if (columnDescriptor.DbName != columnDescriptor.Name)
				{
					sb.Append(" as " + Encapsulate(columnDescriptor.Name));
				}
				flag = true;
			}
		}

		private void BuildKeyWhere<TEntity>(StringBuilder sb, IEnumerable<ColumnDescriptor> idprops)
		{
			ColumnDescriptor[] source = idprops.ToArray();
			for (int i = 0; i < source.Count(); i++)
			{
				string dbName = source.ElementAt(i).DbName;
				sb.AppendFormat("{0} = @{1}", Encapsulate(dbName), source.ElementAt(i).Name);
				if (i < source.Count() - 1)
				{
					sb.AppendFormat(" and ");
				}
			}
		}

		private void BuildWhere<TEntity>(StringBuilder sb, IEnumerable<PropertyInfo> props, object whereConditions = null)
		{
			PropertyInfo[] source = props.ToArray();
			for (int i = 0; i < source.Count(); i++)
			{
				bool flag = false;
				string databaseword = source.ElementAt(i).Name;
				List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeof(TEntity));
				for (int j = 0; j < columnDescriptors.Count; j++)
				{
					if (columnDescriptors.ElementAt(j).Name == source.ElementAt(i).Name)
					{
						databaseword = columnDescriptors.ElementAt(j).DbName;
						if (whereConditions != null && source.ElementAt(i).CanRead && (source.ElementAt(i).GetValue(whereConditions, null) == null || source.ElementAt(i).GetValue(whereConditions, null) == DBNull.Value))
						{
							flag = true;
						}
						break;
					}
				}
				sb.AppendFormat(flag ? "{0} is null" : "{0} = @{1}", Encapsulate(databaseword), source.ElementAt(i).Name);
				if (i < source.Count() - 1)
				{
					sb.AppendFormat(" and ");
				}
			}
		}

		private void BuildInsertValues<TEntity>(StringBuilder sb)
		{
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeof(TEntity));
			for (int i = 0; i < columnDescriptors.Count; i++)
			{
				ColumnDescriptor columnDescriptor = columnDescriptors.ElementAt(i);
				if (!columnDescriptor.AutoIncrement || !(columnDescriptor.TypeName != typeof(string).Name) || !(columnDescriptor.TypeName != typeof(Guid).Name))
				{
					sb.AppendFormat("@{0}", columnDescriptor.Name);
					if (i < columnDescriptors.Count - 1)
					{
						sb.Append(", ");
					}
				}
			}
			if (sb.ToString().EndsWith(", "))
			{
				sb.Remove(sb.Length - 2, 2);
			}
		}

		private void BuildInsertParameters<TEntity>(StringBuilder sb)
		{
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeof(TEntity));
			for (int i = 0; i < columnDescriptors.Count; i++)
			{
				ColumnDescriptor columnDescriptor = columnDescriptors.ElementAt(i);
				if (!columnDescriptor.AutoIncrement || !(columnDescriptor.TypeName != typeof(string).Name) || !(columnDescriptor.TypeName != typeof(Guid).Name))
				{
					sb.Append(Encapsulate(columnDescriptor.DbName));
					if (i < columnDescriptors.Count() - 1)
					{
						sb.Append(", ");
					}
				}
			}
			if (sb.ToString().EndsWith(", "))
			{
				sb.Remove(sb.Length - 2, 2);
			}
		}

		private IEnumerable<ColumnDescriptor> GetUpdateableProperties<TEntity>(IEnumerable<string> updateFields)
		{
			IEnumerable<ColumnDescriptor> source = TableCache.GetColumnDescriptors(typeof(TEntity)).ToArray();
			List<string> list = updateFields?.ToList();
			if (list != null && list.Any())
			{
				IEnumerable<string> fieldsLower = list.Select((string f) => f.ToLower());
				return source.Where((ColumnDescriptor p) => fieldsLower.Contains(p.Name.ToLower()));
			}
			source = source.Where((ColumnDescriptor p) => !p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase));
			source = source.Where((ColumnDescriptor p) => !p.IsPrimaryKey);
			source = source.Where((ColumnDescriptor p) => !p.AutoIncrement);
			return source.Where((ColumnDescriptor p) => !p.NotUpdate);
		}

		private IEnumerable<ColumnDescriptor> GetIdProperties(object entity)
		{
			return from n in TableCache.GetColumnDescriptors(entity.GetType())
				where n.IsPrimaryKey
				select n;
		}

		private string GetTableName(object entity)
		{
			Type type = entity.GetType();
			return GetTableName(type);
		}

		private string GetTableName(Type type)
		{
			TableAttribute table = TableCache.GetTable(type);
			string text = Encapsulate(table.Name);
			if (!string.IsNullOrEmpty(table.Schema))
			{
				string arg = Encapsulate(table.Schema);
				text = $"{arg}.{text}";
			}
			return text;
		}

		private string Encapsulate(string databaseword)
		{
			return string.Format(_sqlDatabaseOptions.Encapsulation, databaseword);
		}

		public Guid SequentialGuid()
		{
			byte[] array = Guid.NewGuid().ToByteArray();
			DateTime now = DateTime.Now;
			array[3] = (byte)now.Year;
			array[2] = (byte)now.Month;
			array[1] = (byte)now.Day;
			array[0] = (byte)now.Hour;
			array[5] = (byte)now.Minute;
			array[4] = (byte)now.Second;
			return new Guid(array);
		}

		public Task<T> GetAsync(object id, bool useMaster = false)
		{
			return GetAsync<T>(id, null, null, useMaster);
		}

		public Task<TEntity> GetAsync<TEntity>(object id, bool useMaster = false)
		{
			return GetAsync<TEntity>(id, null, null, useMaster);
		}

		private async Task<TEntity> GetAsync<TEntity>(object id, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			List<ColumnDescriptor> list = columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList();
			if (!list.Any())
			{
				throw new ArgumentException("Get<T> only supports an entity with a [Key] or Id property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			sb.Append("Select ");
			BuildSelect(sb, columnDescriptors);
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			sb.Append(" where ");
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0)
				{
					sb.Append(" and ");
				}
				sb.AppendFormat("{0} = @{1}", Encapsulate(list[i].DbName), list[i].Name);
			}
			BuildIsDeleted(sb, columnDescriptors);
			DynamicParameters dynParms = (DynamicParameters)(object)new DynamicParameters();
			if (list.Count == 1)
			{
				dynParms.Add("@" + list.First().Name, id, (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
			}
			else
			{
				foreach (ColumnDescriptor item in list)
				{
					dynParms.Add("@" + item.Name, id.GetType().GetProperty(item.Name).GetValue(id, null), (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
				}
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Get<{typeFromHandle}>: {sb} with Id: {id}");
			}
			IEnumerable<TEntity> entity = null;
			if (!useMaster)
			{
				await OpenSlaveConnectionAsync(async delegate (IDbConnection conn)
				{
					entity = (IEnumerable<TEntity>)(await SqlMapper.QueryAsync<TEntity>(conn, sb.ToString(), (object)dynParms, transaction, commandTimeout, (CommandType?)null));
				});
			}
			else
			{
				await OpenConnectionAsync(async delegate (IDbConnection conn)
				{
					entity = (IEnumerable<TEntity>)(await SqlMapper.QueryAsync<TEntity>(conn, sb.ToString(), (object)dynParms, transaction, commandTimeout, (CommandType?)null));
				});
			}
			return ((IEnumerable<TEntity>)entity).FirstOrDefault();
		}

		public Task<IEnumerable<T>> GetListAsync(object whereConditions, bool useMaster = false)
		{
			return GetListAsync<T>(whereConditions, null, null, useMaster);
		}

		public Task<IEnumerable<TEntity>> GetListAsync<TEntity>(object whereConditions, bool useMaster = false)
		{
			return GetListAsync<TEntity>(whereConditions, null, null, useMaster);
		}

		private async Task<IEnumerable<TEntity>> GetListAsync<TEntity>(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			if (!columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList().Any())
			{
				throw new ArgumentException("Entity must have at least one [Key] property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			PropertyInfo[] array = whereConditions.GetAllProperties().ToArray();
			sb.Append("Select ");
			BuildSelect(sb, columnDescriptors);
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			if (array.Any())
			{
				sb.Append(" where ");
				BuildWhere<TEntity>(sb, array, whereConditions);
			}
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"GetList<{typeFromHandle}>: {sb}");
			}
			IEnumerable<TEntity> entities = null;
			if (!useMaster)
			{
				await OpenSlaveConnectionAsync(async delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)(await SqlMapper.QueryAsync<TEntity>(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null));
				});
			}
			else
			{
				await OpenConnectionAsync(async delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)(await SqlMapper.QueryAsync<TEntity>(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null));
				});
			}
			return (IEnumerable<TEntity>)entities;
		}

		public Task<IEnumerable<T>> GetListAsync(string conditions, object parameters = null, bool useMaster = false)
		{
			return GetListAsync<T>(conditions, parameters, null, null, useMaster);
		}

		public Task<IEnumerable<TEntity>> GetListAsync<TEntity>(string conditions, object parameters = null, bool useMaster = false)
		{
			return GetListAsync<TEntity>(conditions, parameters, null, null, useMaster);
		}

		private async Task<IEnumerable<TEntity>> GetListAsync<TEntity>(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			if (!columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList().Any())
			{
				throw new ArgumentException("Entity must have at least one [Key] property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			sb.Append("Select ");
			BuildSelect(sb, columnDescriptors);
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			sb.Append(" " + conditions);
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"GetList<{typeFromHandle}>: {sb}");
			}
			IEnumerable<TEntity> entities = null;
			if (!useMaster)
			{
				await OpenSlaveConnectionAsync(async delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)(await SqlMapper.QueryAsync<TEntity>(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null));
				});
			}
			else
			{
				await OpenConnectionAsync(async delegate(IDbConnection conn)
				{
					entities = (IEnumerable<TEntity>)(await SqlMapper.QueryAsync<TEntity>(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null));
				});
			}
			return (IEnumerable<TEntity>)entities;
		}

		public Task<PagedEntity<T>> GetListPagedAsync(int pageNumber, int pageSize, string conditions, string orderby, object parameters = null, bool useMaster = false)
		{
			return GetListPagedAsync<T>(pageNumber, pageSize, conditions, orderby, parameters, null, null, useMaster);
		}

		public Task<PagedEntity<TEntity>> GetListPagedAsync<TEntity>(int pageNumber, int pageSize, string conditions, string orderby, object parameters = null, bool useMaster = false)
		{
			return GetListPagedAsync<TEntity>(pageNumber, pageSize, conditions, orderby, parameters, null, null, useMaster);
		}

		private async Task<PagedEntity<TEntity>> GetListPagedAsync<TEntity>(int pageNumber, int pageSize, string conditions, string orderby, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			if (string.IsNullOrEmpty(_sqlDatabaseOptions.PagedListSql))
			{
				throw new Exception("GetListPage is not supported with the current SQL Dialect");
			}
			if (pageNumber < 1)
			{
				throw new Exception("Page must be greater than 0");
			}
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			List<ColumnDescriptor> source = columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList();
			if (!source.Any())
			{
				throw new ArgumentException("Entity must have at least one [Key] property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder stringBuilder = new StringBuilder();
			string query = _sqlDatabaseOptions.PagedListSql;
			if (string.IsNullOrEmpty(orderby))
			{
				orderby = Encapsulate(source.First().DbName);
			}
			BuildSelect(stringBuilder, columnDescriptors);
			query = query.Replace("{SelectColumns}", stringBuilder.ToString());
			query = query.Replace("{TableName}", tableName);
			query = query.Replace("{PageNumber}", pageNumber.ToString());
			query = query.Replace("{RowsPerPage}", pageSize.ToString());
			query = query.Replace("{OrderBy}", orderby);
			query = query.Replace("{WhereClause}", conditions);
			query = query.Replace("{IsDeleted}", BuildIsDeleted(null, columnDescriptors, query));
			query = query.Replace("{Offset}", ((pageNumber - 1) * pageSize).ToString());
			string countQuery = _sqlDatabaseOptions.PagedListCountSql;
			countQuery = countQuery.Replace("{TableName}", tableName);
			countQuery = countQuery.Replace("{WhereClause}", conditions);
			countQuery = countQuery.Replace("{IsDeleted}", BuildIsDeleted(null, columnDescriptors, countQuery));
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"GetListPaged<{typeFromHandle}>: {query},{countQuery}");
			}
			PagedEntity<TEntity> entities = (PagedEntity<TEntity>)(object)new PagedEntity<TEntity>();
			((PagedEntity<TEntity>)(object)entities).Items = new List<TEntity>();
			if (!useMaster)
			{
				await OpenSlaveConnectionAsync(async delegate(IDbConnection conn)
				{
					IEnumerable<int> source4 = await SqlMapper.QueryAsync<int>(conn, countQuery, parameters, transaction, commandTimeout, (CommandType?)null);
					((PagedEntity<TEntity>)(object)entities).TotalItems = source4.FirstOrDefault();
					if (((PagedEntity<TEntity>)(object)entities).TotalItems != 0)
					{
						IEnumerable<TEntity> source5 = await SqlMapper.QueryAsync<TEntity>(conn, query, parameters, transaction, commandTimeout, (CommandType?)null);
						((PagedEntity<TEntity>)(object)entities).Items = source5.ToList();
					}
				});
			}
			else
			{
				await OpenConnectionAsync(async delegate(IDbConnection conn)
				{
					IEnumerable<int> source2 = await SqlMapper.QueryAsync<int>(conn, countQuery, parameters, transaction, commandTimeout, (CommandType?)null);
					((PagedEntity<TEntity>)(object)entities).TotalItems = source2.FirstOrDefault();
					if (((PagedEntity<TEntity>)(object)entities).TotalItems != 0)
					{
						IEnumerable<TEntity> source3 = await SqlMapper.QueryAsync<TEntity>(conn, query, parameters, transaction, commandTimeout, (CommandType?)null);
						((PagedEntity<TEntity>)(object)entities).Items = source3.ToList();
					}
				});
			}
			return (PagedEntity<TEntity>)(object)entities;
		}

		public Task<int> InsertAsync(T obj)
		{
			return InsertAsync(obj, null, null);
		}

		public Task<int> InsertAsync<TEntity>(TEntity obj)
		{
			return InsertAsync(obj, null, null);
		}

		public Task<TKey> InsertAsync<TKey>(T obj)
		{
			return InsertAsync<TKey, T>(obj, null, null);
		}

		public Task<TKey> InsertAsync<TKey, TEntity>(TEntity obj)
		{
			return InsertAsync<TKey, TEntity>(obj, null, null);
		}

		private Task<int> InsertAsync<TEntity>(TEntity entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			return InsertAsync<int, TEntity>(entityToInsert, transaction, commandTimeout);
		}

		private async Task<TKey> InsertAsync<TKey, TEntity>(TEntity entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			List<ColumnDescriptor> idProps = GetIdProperties(entityToInsert).ToList();
			if (!idProps.Any())
			{
				throw new ArgumentException("Insert<T> only supports an entity with a [Key] or Id property");
			}
			bool keyHasPredefinedValue = false;
			Type typeFromHandle = typeof(TKey);
			Type underlyingType = Nullable.GetUnderlyingType(typeFromHandle);
			Type keytype = underlyingType ?? typeFromHandle;
			if (keytype != typeof(int) && keytype != typeof(uint) && keytype != typeof(long) && keytype != typeof(ulong) && keytype != typeof(short) && keytype != typeof(ushort) && keytype != typeof(Guid) && keytype != typeof(string))
			{
				throw new Exception("Invalid return type");
			}
			string tableName = GetTableName(entityToInsert);
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("insert into {0}", tableName);
			sb.Append(" (");
			BuildInsertParameters<TEntity>(sb);
			sb.Append(") ");
			sb.Append("values");
			sb.Append(" (");
			BuildInsertValues<TEntity>(sb);
			sb.Append(")");
			if (keytype == typeof(string))
			{
				if (string.IsNullOrEmpty((string)idProps.First().GetKeyValue(entityToInsert)))
				{
					string arg = SequentialGuid().ToString("N");
					idProps.First().SetKeyValue(entityToInsert, arg);
				}
				else
				{
					keyHasPredefinedValue = true;
				}
				sb.Append(";select '" + idProps.First().GetKeyValue(entityToInsert)?.ToString() + "' as id");
			}
			else if (keytype == typeof(Guid))
			{
				if ((Guid)idProps.First().GetKeyValue(entityToInsert) == Guid.Empty)
				{
					Guid guid = SequentialGuid();
					idProps.First().SetKeyValue(entityToInsert, guid);
				}
				else
				{
					keyHasPredefinedValue = true;
				}
				sb.Append(";select '" + idProps.First().GetKeyValue(entityToInsert)?.ToString() + "' as id");
			}
			else if (keytype == typeof(int) || keytype == typeof(long))
			{
				if (Convert.ToInt64(idProps.First().GetKeyValue(entityToInsert)) == 0L)
				{
					sb.Append(";" + _sqlDatabaseOptions.IdentitySql);
				}
				else
				{
					sb.Append(";select " + idProps.First().GetKeyValue(entityToInsert)?.ToString() + " as id");
					keyHasPredefinedValue = true;
				}
			}
			else
			{
				keyHasPredefinedValue = true;
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Insert: {sb}");
			}
			IEnumerable<dynamic> entities = null;
			await OpenConnectionAsync(async delegate(IDbConnection conn)
			{
				entities = await SqlMapper.QueryAsync(conn, sb.ToString(), (object)entityToInsert, transaction, commandTimeout, (CommandType?)null);
			});
			if ((keytype == typeof(Guid) || keytype == typeof(string)) | keyHasPredefinedValue)
			{
				return (TKey)idProps.First().GetKeyValue(entityToInsert);
			}
			dynamic val = entities.First().id;
			if (idProps.First().TypeName == "Int64")
			{
				idProps.First().SetKeyValue(entityToInsert, (long)val);
			}
			else
			{
				idProps.First().SetKeyValue(entityToInsert, (int)val);
			}
			return (TKey)val;
		}

		public async Task InsertBatchAsync<TEntity>(IEnumerable<TEntity> entities)
		{
			string tableName = GetTableName(entities.FirstOrDefault());
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("insert into {0}", tableName);
			sb.Append(" (");
			BuildInsertParameters<TEntity>(sb);
			sb.Append(") ");
			sb.Append("values");
			sb.Append(" (");
			BuildInsertValues<TEntity>(sb);
			sb.Append(")");
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Insert: {sb}");
			}
			await OpenConnectionAsync(async delegate(IDbConnection conn)
			{
				await SqlMapper.ExecuteAsync(conn, sb.ToString(), (object)entities, (IDbTransaction)null, (int?)null, (CommandType?)null);
			});
		}

		public Task<int> UpdateAsync(T obj, IEnumerable<string> updateFields = null)
		{
			return UpdateAsync(obj, updateFields, null, null);
		}

		public Task<int> UpdateAsync<TEntity>(TEntity obj, IEnumerable<string> updateFields = null)
		{
			return UpdateAsync(obj, updateFields, null, null);
		}

		private async Task<int> UpdateAsync<TEntity>(TEntity entityToUpdate, IEnumerable<string> updateFields = null, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			List<ColumnDescriptor> list = GetIdProperties(entityToUpdate).ToList();
			if (!list.Any())
			{
				throw new ArgumentException("Entity must have at least one [Key] or Id property");
			}
			string tableName = GetTableName(entityToUpdate);
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("update {0}", tableName);
			sb.AppendFormat(" set ");
			BuildUpdateSet<TEntity>(sb, updateFields);
			sb.Append(" where ");
			BuildKeyWhere<TEntity>(sb, list);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Update: {sb}");
			}
			int result = 0;
			await OpenConnectionAsync(async delegate(IDbConnection conn)
			{
				result = await SqlMapper.ExecuteAsync(conn, sb.ToString(), (object)entityToUpdate, transaction, commandTimeout, (CommandType?)null);
			});
			return result;
		}

		public Task<int> DeleteAsync(object id, string opName = "", bool isDelete = false)
		{
			return DeleteAsync<T>(id, isDelete, opName);
		}

		public Task<int> DeleteAsync<TEntity>(object id, string opName = "", bool isDelete = false)
		{
			return DeleteAsync<TEntity>(id, isDelete, opName);
		}

		public Task<int> DeleteListAsync(object whereConditions, string opName = "", bool isDelete = false)
		{
			return DeleteListAsync<T>(whereConditions, isDelete, opName);
		}

		public Task<int> DeleteListAsync<TEntity>(object whereConditions, string opName = "", bool isDelete = false)
		{
			return DeleteListAsync<TEntity>(whereConditions, isDelete, opName);
		}

		public Task<int> DeleteListAsync(string conditions, object parameters = null, string opName = "", bool isDelete = false)
		{
			return DeleteListAsync<T>(conditions, isDelete, opName, parameters);
		}

		public Task<int> DeleteListAsync<TEntity>(string conditions, object parameters = null, string opName = "", bool isDelete = false)
		{
			return DeleteListAsync<TEntity>(conditions, isDelete, opName, parameters);
		}

		private async Task<int> DeleteAsync<TEntity>(object id, bool isDelete = false, string opName = "", IDbTransaction transaction = null, int? commandTimeout = null)
		{
			Type typeFromHandle = typeof(TEntity);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			List<ColumnDescriptor> list = columnDescriptors.Where((ColumnDescriptor n) => n.IsPrimaryKey).ToList();
			ColumnDescriptor columnDescriptor = columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "IsDeleted");
			if (!list.Any())
			{
				throw new ArgumentException("Delete<T> only supports an entity with a [Key] or Id property");
			}
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			if (!isDelete && columnDescriptor != null)
			{
				if (columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "Operator") != null && !string.IsNullOrEmpty(opName))
				{
					sb.AppendFormat("Update {0} set IsDeleted=1,Operator={1} where IsDeleted=0 and ", tableName, opName);
				}
				else
				{
					sb.AppendFormat("Update {0} set IsDeleted=1 where IsDeleted=0 and ", tableName);
				}
			}
			else
			{
				sb.AppendFormat("Delete from {0} where ", tableName);
			}
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0)
				{
					sb.Append(" and ");
				}
				sb.AppendFormat("{0} = @{1}", Encapsulate(list[i].DbName), list[i].Name);
			}
			DynamicParameters dynParms = (DynamicParameters)(object)new DynamicParameters();
			if (list.Count == 1)
			{
				dynParms.Add("@" + list.First().Name, id, (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
			}
			else
			{
				foreach (ColumnDescriptor item in list)
				{
					dynParms.Add("@" + item.Name, id.GetType().GetProperty(item.Name).GetValue(id, null), (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
				}
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"Delete<{typeFromHandle}> {sb}");
			}
			int result = 0;
			await OpenConnectionAsync(async delegate(IDbConnection conn)
			{
				result = await SqlMapper.ExecuteAsync(conn, sb.ToString(), (object)dynParms, transaction, commandTimeout, (CommandType?)null);
			});
			return result;
		}

		private async Task<int> DeleteListAsync<TEntity>(object whereConditions, bool isDelete = false, string opName = "", IDbTransaction transaction = null, int? commandTimeout = null)
		{
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			ColumnDescriptor columnDescriptor = columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "IsDeleted");
			StringBuilder sb = new StringBuilder();
			if (!isDelete && columnDescriptor != null)
			{
				if (columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "Operator") != null && !string.IsNullOrEmpty(opName))
				{
					sb.AppendFormat("Update {0} set IsDeleted=1,Operator={1} where IsDeleted=0 ", tableName, opName);
				}
				else
				{
					sb.AppendFormat("Update {0} set IsDeleted=1 where IsDeleted=0 ", tableName);
				}
			}
			else
			{
				sb.AppendFormat("Delete from {0} where 1=1 ", tableName);
			}
			PropertyInfo[] array = whereConditions.GetAllProperties().ToArray();
			if (array.Any())
			{
				sb.Append(" and ");
				BuildWhere<TEntity>(sb, array);
			}
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"DeleteList<{typeFromHandle}> {sb}");
			}
			int deleteCount = 0;
			await OpenConnectionAsync(async delegate(IDbConnection conn)
			{
				deleteCount = await SqlMapper.ExecuteAsync(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null);
			});
			return deleteCount;
		}

		private async Task<int> DeleteListAsync<TEntity>(string conditions, bool isDelete = false, string opName = "", object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)
		{
			if (string.IsNullOrEmpty(conditions))
			{
				throw new ArgumentException("DeleteList<T> requires a where clause");
			}
			if (!conditions.ToLower().Contains("where"))
			{
				throw new ArgumentException("DeleteList<T> requires a where clause and must contain the WHERE keyword");
			}
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			ColumnDescriptor columnDescriptor = columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "IsDeleted");
			StringBuilder sb = new StringBuilder();
			if (!isDelete && columnDescriptor != null)
			{
				if (columnDescriptors.FirstOrDefault((ColumnDescriptor o) => o.Name == "Operator") != null && !string.IsNullOrEmpty(opName))
				{
					sb.AppendFormat("Update {0} set IsDeleted=1,Operator={1}", tableName, opName);
				}
				else
				{
					sb.AppendFormat("Update {0} set IsDeleted=1", tableName);
				}
			}
			else
			{
				sb.AppendFormat("Delete from {0}", tableName);
			}
			sb.Append(" " + conditions);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"DeleteList<{typeFromHandle}> {sb}");
			}
			int deleteCount = 0;
			await OpenConnectionAsync(async delegate(IDbConnection conn)
			{
				deleteCount = await SqlMapper.ExecuteAsync(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null);
			});
			return deleteCount;
		}

		public Task<int> RecordCountAsync(string conditions, object parameters = null, bool useMaster = false)
		{
			return RecordCountAsync<T>(conditions, parameters, null, null, useMaster);
		}

		public Task<int> RecordCountAsync<TEntity>(string conditions, object parameters = null, bool useMaster = false)
		{
			return RecordCountAsync<TEntity>(conditions, parameters, null, null, useMaster);
		}

		public Task<int> RecordCountAsync(object whereConditions, bool useMaster = false)
		{
			return RecordCountAsync<T>(whereConditions, null, null, useMaster);
		}

		public Task<int> RecordCountAsync<TEntity>(object whereConditions, bool useMaster = false)
		{
			return RecordCountAsync<TEntity>(whereConditions, null, null, useMaster);
		}

		private async Task<int> RecordCountAsync<TEntity>(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			sb.Append("Select count(1)");
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			sb.Append(" " + conditions);
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"RecordCount<{typeFromHandle}>: {sb}");
			}
			int count = 0;
			if (!useMaster)
			{
				await OpenSlaveConnectionAsync(async delegate(IDbConnection conn)
				{
					count = await SqlMapper.ExecuteScalarAsync<int>(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null);
				});
			}
			else
			{
				await OpenConnectionAsync(async delegate(IDbConnection conn)
				{
					count = await SqlMapper.ExecuteScalarAsync<int>(conn, sb.ToString(), parameters, transaction, commandTimeout, (CommandType?)null);
				});
			}
			return count;
		}

		private async Task<int> RecordCountAsync<TEntity>(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null, bool useMaster = false)
		{
			Type typeFromHandle = typeof(TEntity);
			string tableName = GetTableName(typeFromHandle);
			StringBuilder sb = new StringBuilder();
			PropertyInfo[] array = whereConditions.GetAllProperties().ToArray();
			sb.Append("Select count(1)");
			sb.AppendFormat(_sqlDatabaseOptions.FromSql, tableName);
			if (array.Any())
			{
				sb.Append(" where ");
				BuildWhere<TEntity>(sb, array, (TEntity)Activator.CreateInstance(typeof(TEntity)));
			}
			List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeFromHandle);
			BuildIsDeleted(sb, columnDescriptors);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine($"RecordCount<{typeFromHandle}>: {sb}");
			}
			int count = 0;
			if (!useMaster)
			{
				await OpenSlaveConnectionAsync(async delegate(IDbConnection conn)
				{
					count = await SqlMapper.ExecuteScalarAsync<int>(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null);
				});
			}
			else
			{
				await OpenConnectionAsync(async delegate(IDbConnection conn)
				{
					count = await SqlMapper.ExecuteScalarAsync<int>(conn, sb.ToString(), whereConditions, transaction, commandTimeout, (CommandType?)null);
				});
			}
			return count;
		}

		public async Task<IEnumerable<T>> SelectAsync(IQuery<T> query)
		{
			Clause clause = SqlBuilder.Instance.SelectAsync(query);
			if (Debugger.IsAttached)
			{
				Trace.WriteLine(clause.Sql);
			}
			if (string.IsNullOrEmpty(clause.Sql))
			{
				return Enumerable.Empty<T>();
			}
			DynamicParameters dynamicParameters = (DynamicParameters)(object)new DynamicParameters();
			foreach (DapperExtensionsNew.Data.ParameterInfo parameter in clause.Parameters.GetParameters())
			{
				dynamicParameters.Add(parameter.Name, parameter.Value, (System.Data.DbType?)null, (ParameterDirection?)null, (int?)null, (byte?)null, (byte?)null);
			}
			IEnumerable<T> result = Enumerable.Empty<T>();
			if (!query.UseMaster.GetValueOrDefault())
			{
				await OpenSlaveConnectionAsync(Func);
			}
			else
			{
				await OpenConnectionAsync(Func);
			}
			return result;
			async Task Func(IDbConnection conn)
			{
				GridReader grid = await SqlMapper.QueryMultipleAsync(conn, clause.Sql, (object)dynamicParameters, (IDbTransaction)null, (int?)null, (CommandType?)null);
				result = ((await grid.ReadAsync<T>(true)) ?? Enumerable.Empty<T>());
				if (clause.Paging)
				{
					IDictionary<string, object> dictionary = (await grid.ReadAsync<object>(true)).FirstOrDefault() as IDictionary<string, object>;
					query.Count = Convert.ToInt32((dictionary != null) ? dictionary.Values.ElementAt(0) : null);
				}
			}
		}
	}
}
